package com.turingoal.common.util.lucene;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.search.highlight.Formatter;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.TokenSources;
import org.apache.lucene.store.Directory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * LuceneHelper 数据流没有做关闭处理 需要完善 XXXXXXXX
 */
public class LuceneHelper {
	private static final String STARTTAG = "<font color='red'>";
	private static final String ENDTAG = "</font>";
	private static Formatter htmlFormatter = new SimpleHTMLFormatter(STARTTAG, ENDTAG);
	public Directory luceneDrectory;
	public Analyzer luceneAnalyzer;
	public IndexWriter indexWriter;
	private final Logger logger = LoggerFactory.getLogger(LuceneHelper.class);

	public LuceneHelper(Directory luceneDrectory, IndexWriter indexWriter, Analyzer luceneAnalyzer) {
		super();
		this.luceneDrectory = luceneDrectory;
		this.luceneAnalyzer = luceneAnalyzer;
		this.indexWriter = indexWriter;
	}

	private IndexReader getIndexReader() throws IOException {
		return DirectoryReader.open(luceneDrectory);
	}

	public IndexSearcher getIndexSearcher() throws IOException {
		return new IndexSearcher(getIndexReader());
	}

	/**
	 * 添加索引
	 * */
	public void addIndex(Document doc) {
		try {
			indexWriter.addDocument(doc);
			indexWriter.commit();// 提交数据
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 批量添加索引
	 * */
	public void addIndexs(List<Document> docs) {
		try {
			for (int i = 0, length = docs.size(); i < length; i++) {
				indexWriter.addDocument(docs.get(i));
			}
			indexWriter.commit();// 提交数据
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/***
	 * 查询数据总量
	 */
	public int findIndexDbCount(String indexFile) {
		int total = 0;
		try {
			IndexReader reader = getIndexReader();
			total = reader.numDocs();// 数据总量
			reader.close();// 释放资源
		} catch (Exception e) {
			e.printStackTrace();
		}
		return total;
	}

	/**
	 * 更新索引
	 */
	public void updateIndex(String id, Document d) {
		try {
			indexWriter.updateDocument(new Term("id", id), d);
			indexWriter.commit();// 提交数据
		} catch (IOException e) {
			logger.error("更新索引失败，id=" + id);
			e.printStackTrace();
		}
	}

	/**
	 * 删除索引
	 */
	public String deleteIndex(String id) {
		Query q = new TermQuery(new Term("id", id));
		try {
			indexWriter.deleteDocuments(q); // 删除指定ID的Document
			indexWriter.commit();// 提交数据
		} catch (IOException e) {
			logger.error("删除索引失败，id=" + id);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 删除全部索引
	 */
	public void deleteAllIndexes() {
		try {
			indexWriter.deleteAll();
			indexWriter.commit();
		} catch (IOException e) {
			logger.error("删除全部索引失败");
			e.printStackTrace();
		}
	}

	/**
	 * 分页加排序查询的方法
	 */
	public LuceneSearchResultBean search(Query query, Sort sort, int start, int limit) {
		if (query == null) {
			return null;
		}
		List<Document> docs = new ArrayList<Document>();
		IndexSearcher search;
		// 查询终止记录位置
		// int end = Math.min(start + limit, scoreDocs.length);
		try {
			TopFieldCollector c = TopFieldCollector.create(sort, start + limit, false, false, false);
			search = getIndexSearcher(); // 初始化查询组件
			search.search(query, c);
			ScoreDoc[] sd = c.topDocs(start, limit).scoreDocs;
			if (sd == null || sd.length < 1) {
				return null;
			}
			Document doc;
			for (int i = 0, length = sd.length; i < length; i++) {
				int z = sd[i].doc;// 获取每一个文档编号
				doc = search.doc(z);// 获取文档
				docs.add(doc);
			}
			return new LuceneSearchResultBean(c.getTotalHits(), docs);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 高亮
	 */
	public String highLight(Query query, Document doc, String field, String text) {
		Highlighter highlighter;
		Scorer scorer = new QueryScorer(query);
		Fragmenter fragmenter = new SimpleFragmenter();
		highlighter = new Highlighter(htmlFormatter, scorer);// 高亮分析器
		highlighter.setTextFragmenter(fragmenter);
		TokenStream token = TokenSources.getTokenStream(field, text, luceneAnalyzer);// 获取tokenstream
		try {
			text = highlighter.getBestFragment(token, text);
		} catch (IOException | InvalidTokenOffsetsException e) {
			e.printStackTrace();
		}
		return text;
	}
}